//
//  AppController.m
//  iLogColor
//
//  Copyright 2009 Reinier Haasjes 
//  
//  This file is covered by the MIT License.
//  See LICENSE for more information.
//

#import "AppController.h"
#import "RHColorizer.h"
#import "debug.h"

@implementation AppController

/**
 ** Initialisation
 **/
- (id)init 
{
	debug_NSLog(@"init");
	
    self = [super init];
    [[NSNotificationCenter defaultCenter] addObserver:self 
											 selector:@selector(finishedTask:) 
												 name:NSTaskDidTerminateNotification 
											   object:nil];
	
	[self checkDefaults];
	
	logTask = nil; // This is a good time to initialize the pointer
	[self setTaskIsRunning:NO];
	return self;
}

- (void)windowDidBecomeMain:(NSNotification *)notification
{
	debug_NSLog(@"windowDidBecomeMain");	
}

- (void)awakeFromNib
{
	debug_NSLog(@"awakeFromNib");
	
    NSRect screenRect;
	NSRect windowRect;

	// Put preference window in the center
	[prefsWindow center];

	// Add trackingarea 
	NSTrackingArea *area = [[[NSTrackingArea alloc] 
							 initWithRect: [scrollView bounds] 
							 options: (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways) 
							 owner: self 
							 userInfo: nil] autorelease];
	[scrollView addTrackingArea:area];
	
	// Asume mouse is not in view
	[self setMouseOver:FALSE];
	
	// Set background color
	[self setBackground];
	
	// Get window size
	screenRect = [[NSScreen mainScreen] frame];
	windowRect = [window frame];
	
	// Set Window size
	windowRect.size.height = 217;	// 14 lines
	windowRect.size.width = screenRect.size.width * 0.8;
	
	// Position & scale window
#ifdef _DEBUG
	[window center];
#else
	[window setFrame:windowRect display:YES];
	NSRect mainScreenFrame = [[NSScreen mainScreen] visibleFrame]; 
	[window setFrameOrigin: mainScreenFrame.origin];
#endif
	
	// Initial window title
	[self setTitle];
/*
	[window setTitle:@"Test"];
	NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
	[window setTitle:appName];
	[window setTitle:[appName stringByAppendingString:@" - DISCONNECTED"]];
*/
	
	// Put window in the front
    [window makeKeyAndOrderFront:nil];
	
	// 'Disable' line wrap
	NSTextContainer *textContainer = [logOutput textContainer];
	NSSize theSize = [textContainer containerSize];
	theSize.width = 1.0e7;
	[textContainer setContainerSize:theSize];
	[textContainer setWidthTracksTextView:NO];
}

- (void)applicationDidFinishLaunching:(NSNotification*)notification 
{
	debug_NSLog(@"applicationDidFinishLaunching");
	
	// Auto start task is requested (in preferences)
	if ([[NSUserDefaults standardUserDefaults] boolForKey:@"connectAtStartup"])
		[self startTask];
	
	// DEBUG TESTING
	NSTextStorage *textStorage = [logOutput textStorage];
	RHColorizer *colorizer = [[RHColorizer alloc] init];
	NSAttributedString *text = [colorizer Makeup:@"kernel"];
	[textStorage appendAttributedString:text];
}

- (void)applicationDidBecomeActive:(NSNotification *)aNotification
{
	debug_NSLog(@"applicationDidBecomeActive");
}

- (void)applicationWillTerminate:(NSApplication *)sender
{
	debug_NSLog(@"applicationWillTerminate");
}

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
	debug_NSLog(@"applicationShouldTerminate");
	[self stopTask];
	
	return NSTerminateNow;
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed: (NSApplication *)theApplication 
{
	// Connect 'File's Owner' -> AppController; "delegate"
    return YES;
}

/**
 ** Functions
 **/
- (void)checkDefaults
{
	debug_NSLog(@"checkDefaults");
	
	// Open defaults
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

	// Check lastLines
	if ([defaults objectForKey:@"lastLines"] == nil)
	{
		debug_NSLog(@"Set default 10 for lastLines");
		[defaults setObject:@"10" forKey:@"lastLines"];
	}
	
	// Check forground color
	if ([defaults objectForKey:@"foregroundColor"] == nil)
	{
		debug_NSLog(@"Set default white for foregroundColor");
		
		NSData *colorData=[NSArchiver archivedDataWithRootObject:[NSColor whiteColor]];
		[defaults setObject:colorData forKey:@"foregroundColor"];
	}
	
	// Check background color
	if ([defaults objectForKey:@"backgroundColor"] == nil)
	{
		debug_NSLog(@"Set default black for backgroundColor");
		
		NSData *colorData=[NSArchiver archivedDataWithRootObject:[NSColor blackColor]];
		[defaults setObject:colorData forKey:@"backgroundColor"];
	}

	// Check Connect at startup
	if ([defaults objectForKey:@"connectAtStartup"] == nil)
	{	
		debug_NSLog(@"Set default FALSE for connectAtStartup");
	
		[defaults setObject:FALSE forKey:@"connectAtStartup"];
	}

	// Release defaults
	//[defaults release];
	
}

- (void)stopTask
{
	debug_NSLog(@"stopTask");
	if (![self taskIsRunning]) //Only continue if running
		return;
		
	// Terminate task
	[logTask terminate];
}

- (void)startTask
{
	debug_NSLog(@"startTask");
	
	if ([self taskIsRunning]) //Only continue if not running
		return;
	
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	
	// Check Logfile variable
	if ([defaults objectForKey:@"logfile"] == nil)
	{
		NSAlert* alert = [NSAlert new];
		[alert setAlertStyle:NSWarningAlertStyle];
		[alert setMessageText:     @"Logfile not set"];
		[alert setInformativeText: @"Unable to display logfile if variable is not set"];
		
		[alert runModal];
		[alert release];
		
		[defaults release];
		return;
	}	
	
	// Initialize task
	logTask=[[NSTask alloc] init];
//	copyThread=[[NSThread alloc] init];
	logPipe=[[NSPipe alloc] init];
	
	// Set Task
	if ([defaults objectForKey:@"server"] == nil)
	{
		[logTask setLaunchPath:@"/usr/bin/tail"];
		[logTask setArguments:[NSArray arrayWithObjects:
							   @"-n", 
							   [defaults stringForKey:@"lastLines"], 
							   @"-f", 
							   [defaults stringForKey:@"logfile"],
							   nil]];
	} else {
		[logTask setLaunchPath:@"/usr/bin/ssh"];
		[logTask setArguments:[NSArray arrayWithObjects:
							   [defaults stringForKey:@"server"], 
							   @"tail", 
							   @"-n", 
							   [defaults stringForKey:@"lastLines"], 
							   @"-f", 
							   [defaults stringForKey:@"logfile"],
							   nil]];
	}
	
	[logTask setStandardOutput:logPipe];
    logHandle=[logPipe fileHandleForReading];
	
	// Excecute task
	[logTask launch];
	
	//debug_NSLog(@"PID: %@", (char *)[logTask processIdentifier]);
	debug_NSLog([NSString stringWithFormat:@"processID=%d",[logTask processIdentifier]]);
	
	// Create thread for copy data
	copyThread = [[NSThread alloc] initWithTarget:self
										 selector:@selector(dataAvailable:) object:logHandle];
	[copyThread start];
	
	[self setTaskIsRunning:YES];
		
	// set new window title
	[self setTitle];

	//[defaults release];
}

- (void)setBackground
{
	debug_NSLog(@"setBackground");

	[logOutput setBackgroundColor:(NSColor *)[NSUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] dataForKey:@"backgroundColor"]]];
}

- (void)setTitle
{
	debug_NSLog(@"setTitle");
	
	NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
	if ([self taskIsRunning]) {
		[window setTitle:appName];
	}else {
		[window setTitle:[appName stringByAppendingString:@" *DISCONNECTED*"]];
	}
}
- (void)finishedTask:(NSNotification *)aNotification 
{
	debug_NSLog(@"finishedTask");
	
    [logPipe release];
    [logTask release];
	logTask=nil; // Just in case...
	
	[self setTaskIsRunning:NO];
	
	// set new window title
	[self setTitle];
}

- (void)dataAvailable:(NSFileHandle*)handle 
{
	debug_NSLog(@"dataAvailable");

	// Create Autorelease Pool for thread
	NSAutoreleasePool *threadPool=[[NSAutoreleasePool alloc] init];
	
	// Constants
	NSInteger overflowLength = 20000;
	NSInteger cutLength = 1000;

	// Initialize
    NSData *data;
	int arrayCounter, i;
	RHColorizer *colorizer = [[RHColorizer alloc] init];
   	
	while([data=[handle availableData] length]) // until EOF (check reference)
	{ 
//		debug_NSLog(@"dataAvailable - loop run");

		// Create Autorelease pool for loop
		// Use loopPool because of lots of temporary objects.
		NSAutoreleasePool *loopPool=[[NSAutoreleasePool alloc] init];
		NSTextStorage *textStorage = [logOutput textStorage];
		
		// Init
//		NSData *rtfData;
		NSAttributedString *rtfData;
		NSString *logLine;
		NSString *logLines=[[NSString alloc] initWithData:data
												 encoding:NSASCIIStringEncoding]; 
//		NSInteger logLength=[[logOutput string] length];
//        NSRange theEnd=NSMakeRange([[logOutput string] length],0);
        NSRange theEnd=NSMakeRange([[textStorage string] length],0);
//		NSRange theBegin=NSMakeRange(0, cutLength);
		
		// Split up lines
		NSArray *logLinesArray = [logLines componentsSeparatedByString:@"\n"];
		
		// Proces 1 line at a time
		arrayCounter = [logLinesArray count];
		for (i=0; i < arrayCounter-1; i++)		// skip last line
		{
			// Only process logline < 0 characters (/skip last line)
			logLine = [[logLinesArray objectAtIndex:i] stringByAppendingString:@"\n"];
			
			// Colorize string
			rtfData = [colorizer Makeup:logLine];

			// Put string in window
//			NSInteger length = [rtfData length];
//			if (rtfData != nil && length != 0) {
				if (rtfData != nil) {
				//[logOutput replaceCharactersInRange:theEnd withRTF:rtfData]; // append new string to the end
				[textStorage appendAttributedString:rtfData];
//				theEnd.location+=[logLine length]; // the end has moved
			}
			
		}

		/*
		// Remove head of text
		if (logLength > overflowLength) {
			[logOutput replaceCharactersInRange:theBegin withString:@""];
			theEnd.location=[[logOutput string] length];
		}
		*/
		
#ifdef _DEBUG
		[window setTitle:[[NSNumber numberWithInt:theEnd.location] stringValue]];
#endif		

		// Put scrollrange at the end (if Mouse is NOT over)
		if (![self mouseOver]) {
			[logOutput scrollRangeToVisible:theEnd];
		}
		
		// Cleanup
		//[logLinesArray release];
		[logLines release];
		
		// Release loopPool
		[loopPool release];
	}
	
	// Cleanup
	[colorizer release];
	
	// Release threadPool
    [threadPool drain];
	
}

- (void)mouseEntered:(NSEvent *)theEvent
{
	debug_NSLog(@"mouseEntered:");
	[self setMouseOver:TRUE];
}

- (void)mouseExited:(NSEvent *)theEvent
{
	debug_NSLog(@"mouseExited:");
	[self setMouseOver:FALSE];

	// Copy selected text to Pasteboard
	NSRange selRange = [logOutput selectedRange];
	if (selRange.length != 0) {
		debug_NSLog(@"Copying selected text to pasteboard");
		NSArray *types = [NSArray arrayWithObjects: NSStringPboardType, nil];
		NSPasteboard *pb = [NSPasteboard generalPasteboard];
		[logOutput writeSelectionToPasteboard:pb types:types];
		[logOutput setSelectedRange:NSMakeRange(0, 0)];	// deselect text
	}	
}

/**
 ** Binding Functions
 **/
- (BOOL)taskIsRunning
{
	return taskIsRunning;
}

- (void)setTaskIsRunning:(BOOL)isRunning;
{
	taskIsRunning = isRunning;
}

/**
 ** Actions
 **/
- (IBAction)connect:(id)sender
{
	debug_NSLog(@"connect");
	[self startTask];
}

- (IBAction)disconnect:(id)sender
{
	debug_NSLog(@"disconnect");
	[self stopTask];
}

@synthesize mouseOver;

@end
